   #include <gst/gst.h>
   /* Functions below print the Capabilities in a human-friendly format */
   static gboolean print_field (GQuark field, const GValue * value, gpointer pfx) {
     gchar *str = gst_value_serialize (value);

     g_print ("%s %15s: %s\n", (gchar *) pfx, g_quark_to_string (field), str);
     g_free (str);
     return TRUE;
   }

   static void print_caps (const GstCaps * caps, const gchar * pfx) {
     guint i;

     g_return_if_fail (caps != NULL);

     if (gst_caps_is_any (caps)) {
       g_print ("%sANY\n", pfx);
       return;
     }
     if (gst_caps_is_empty (caps)) {
       g_print ("%sEMPTY\n", pfx);
       return;
     }

     for (i = 0; i < gst_caps_get_size (caps); i++) {
       GstStructure *structure = gst_caps_get_structure (caps, i);

       g_print ("%s%s\n", pfx, gst_structure_get_name (structure));
       gst_structure_foreach (structure, print_field, (gpointer) pfx);
     }
   }

   /* Prints information about a Pad Template, including its Capabilities */
   static void print_pad_templates_information (GstElementFactory * factory) {
     const GList *pads;
     GstStaticPadTemplate *padtemplate;

     g_print ("Pad Templates for %s:\n", gst_element_factory_get_longname (factory));
     if (!gst_element_factory_get_num_pad_templates (factory)) {
       g_print (" none\n");
       return;
     }

     pads = gst_element_factory_get_static_pad_templates (factory);
     while (pads) {
       padtemplate = pads->data;
       pads = g_list_next (pads);

       if (padtemplate->direction == GST_PAD_SRC)
         g_print (" SRC template: '%s'\n", padtemplate->name_template);
       else if (padtemplate->direction == GST_PAD_SINK)
         g_print (" SINK template: '%s'\n", padtemplate->name_template);
       else
         g_print (" UNKNOWN!!! template: '%s'\n", padtemplate->name_template);

       if (padtemplate->presence == GST_PAD_ALWAYS)
         g_print (" Availability: Always\n");
       else if (padtemplate->presence == GST_PAD_SOMETIMES)
         g_print (" Availability: Sometimes\n");
       else if (padtemplate->presence == GST_PAD_REQUEST)
         g_print (" Availability: On request\n");
       else
         g_print (" Availability: UNKNOWN!!!\n");

       if (padtemplate->static_caps.string) {
         GstCaps *caps;
         g_print (" Capabilities:\n");
         caps = gst_static_caps_get (&padtemplate->static_caps);
         print_caps (caps, " ");
         gst_caps_unref (caps);

       }

       g_print ("\n");
     }
   }

   /* Shows the CURRENT capabilities of the requested pad in the given element */
   static void print_pad_capabilities (GstElement *element, gchar *pad_name) {
     GstPad *pad = NULL;
     GstCaps *caps = NULL;

     /* Retrieve pad */
     pad = gst_element_get_static_pad (element, pad_name);
     if (!pad) {
       g_printerr ("Could not retrieve pad '%s'\n", pad_name);
       return;
     }

     /* Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet) */
     caps = gst_pad_get_current_caps (pad);
     if (!caps)
       caps = gst_pad_query_caps (pad, NULL);

     /* Print and free */
     g_print ("Caps for the %s pad:\n", pad_name);
     print_caps (caps, " ");
     gst_caps_unref (caps);
     gst_object_unref (pad);
   }

   int main(int argc, char *argv[]) {
     GstElement *pipeline, *source, *sink;
     GstElementFactory *source_factory, *sink_factory;
     GstBus *bus;
     GstMessage *msg;
     GstStateChangeReturn ret;
     gboolean terminate = FALSE;

     /* Initialize GStreamer */
     gst_init (&argc, &argv);

     /* Create the element factories */
     source_factory = gst_element_factory_find ("audiotestsrc");
     sink_factory = gst_element_factory_find ("autoaudiosink");
     if (!source_factory || !sink_factory) {
       g_printerr ("Not all element factories could be created.\n");
       return -1;
     }

     /* Print information about the pad templates of these factories */
     print_pad_templates_information (source_factory);
     print_pad_templates_information (sink_factory);

     /* Ask the factories to instantiate actual elements */
     source = gst_element_factory_create (source_factory, "source");
     sink = gst_element_factory_create (sink_factory, "sink");

     /* Create the empty pipeline */
     pipeline = gst_pipeline_new ("test-pipeline");

     if (!pipeline || !source || !sink) {
       g_printerr ("Not all elements could be created.\n");
       return -1;
     }

     /* Build the pipeline */
     gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
     if (gst_element_link (source, sink) != TRUE) {
       g_printerr ("Elements could not be linked.\n");
       gst_object_unref (pipeline);
       return -1;
     }

     /* Print initial negotiated caps (in NULL state) */
     g_print ("In NULL state:\n");
     print_pad_capabilities (sink, "sink");

     /* Start playing */
     ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
     if (ret == GST_STATE_CHANGE_FAILURE) {
       g_printerr ("Unable to set the pipeline to the playing state (check the bus for error messages).\n");
     }

     /* Wait until error, EOS or State Change */
     bus = gst_element_get_bus (pipeline);
     do {
       msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS |
           GST_MESSAGE_STATE_CHANGED);

       /* Parse message */
       if (msg != NULL) {
         GError *err;
         gchar *debug_info;

         switch (GST_MESSAGE_TYPE (msg)) {
           case GST_MESSAGE_ERROR:
             gst_message_parse_error (msg, &err, &debug_info);
             g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
             g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
             g_clear_error (&err);
             g_free (debug_info);
             terminate = TRUE;
             break;
           case GST_MESSAGE_EOS:
             g_print ("End-Of-Stream reached.\n");
             terminate = TRUE;
             break;
           case GST_MESSAGE_STATE_CHANGED:
             /* We are only interested in state-changed messages from the pipeline */
             if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline)) {
               GstState old_state, new_state, pending_state;
               gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
               g_print ("\nPipeline state changed from %s to %s:\n",
                   gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
               /* Print the current capabilities of the sink element */
               print_pad_capabilities (sink, "sink");
             }
             break;
           default:
             /* We should not reach here because we only asked for ERRORs, EOS and STATE_CHANGED */
             g_printerr ("Unexpected message received.\n");
             break;
         }
         gst_message_unref (msg);
       }
     } while (!terminate);

     /* Free resources */
     gst_object_unref (bus);
     gst_element_set_state (pipeline, GST_STATE_NULL);
     gst_object_unref (pipeline);
     gst_object_unref (source_factory);
     gst_object_unref (sink_factory);
     return 0;
   }
